﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using Cl.Utils.Helper;
using Cl.Entity.DataBaseEntity.User;
using Cl.Repository;
using Cl.WebApi.Controllers;
using Cl.Utils;

namespace Cl.WebApi.Authorization.WebApiFilter
{
    /// <summary>
    /// webapi 拦截类
    /// </summary>
    public class AuthAttributeFilter : IAuthorizationFilter
    {
        #region 构造函数
        private ClRepository<UserLogin> _accountLoginRepository;

        private readonly string _baseApiKey;
        private readonly string _openApiKey;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="accountLoginRepository"></param>
        public AuthAttributeFilter(ClRepository<UserLogin> accountLoginRepository)
        {
            _accountLoginRepository = accountLoginRepository;


            _baseApiKey = ConfigHelper.GetSection("BaseApiSecurityToken");
            _openApiKey = ConfigHelper.GetSection("OpenApiSecurityToken");
        }

        #endregion

        /// <summary>
        /// 权限认证
        /// </summary>
        /// <param name="context"></param>
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            if (GlobalService.SystemConfigGlobal.EnableSafeMode)
            {
                var headerToken = context.HttpContext.Request.Headers["XunPaiKey"];
                //如果是openapi，放行
                var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
                var controllerType = actionDescriptor?.ControllerTypeInfo;
                var isOpenBaseController = controllerType?.BaseType?.Name == typeof(OpenBaseController).Name;
                if (isOpenBaseController)
                {
                    if (headerToken != _openApiKey)
                    {
                        context.Result = new ContentResult() { StatusCode = StatusCodes.Status401Unauthorized, Content = "请携带正确的OpenToken" };
                        return;
                    }
                    return;//放行
                }

                if (headerToken != _baseApiKey)
                {
                    context.Result = new ContentResult() { StatusCode = StatusCodes.Status401Unauthorized, Content = "请携带正确的BaseToken" };
                    return;
                }
            }

            //如果忽略权限验证，放行
            if (HasAllowAnonymous(context))
            {
                return;
            }


            if (GlobalService.SystemConfigGlobal.EnableSafeMode)
            {
                var token = context.HttpContext.Request.Headers["authorization"];
                var accountData = JwtHelper.JWTDecode(token);
                if (accountData == null || accountData.UserId == 0)
                {
                    if (GlobalService.SystemConfigGlobal.EnableSafeMode)
                    {
                        context.Result = new ContentResult() { StatusCode = StatusCodes.Status401Unauthorized, Content = "账号无效或已过期" };
                        return;
                    }
                }

                //判断是否过期
                var loginInfo = _accountLoginRepository.GetFirst(p => p.Account == accountData.Account);
                if (loginInfo == null || string.IsNullOrEmpty(loginInfo.Token) || loginInfo.ExpireTime < DateTime.Now || loginInfo.Token != token.ToString().Split(" ")[1])
                {
                    if (GlobalService.SystemConfigGlobal.EnableSafeMode)
                    {
                        context.Result = new ContentResult() { StatusCode = StatusCodes.Status401Unauthorized, Content = "账号无效或已过期" };
                        return;
                    }
                }

                //过期前15分钟内操作，延迟60分钟过期
                if ((loginInfo.ExpireTime - DateTime.Now).TotalMinutes < 30)
                {
                    UpdateExpireTime(loginInfo.Id, DateTime.Now.AddMinutes(60));
                }
            }
        }

        private bool HasAllowAnonymous(AuthorizationFilterContext context)
        {
            var endpoint = context.HttpContext.GetEndpoint();
            if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 更新过期时间
        /// </summary>
        /// <param name="id"></param>
        /// <param name="expireTime"></param>
        /// <returns></returns>
        public bool UpdateExpireTime(long id, DateTime expireTime)
        {
            var sql = _accountLoginRepository.AsUpdateable().SetColumns(p => p.ExpireTime == expireTime).Where(p => p.Id == id);
            return sql.ExecuteCommand() > 0;
        }
    }
}
